package Risk.Moteur;

//~--- non-JDK imports --------------------------------------------------------

import org.omg.PortableServer.THREAD_POLICY_ID;

//~--- JDK imports ------------------------------------------------------------

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Random;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *  Class description
 *     @version    1.0, 07/12/26
 *   @author     Alexandre LIGUORI
 */
public class Pays {
    public static int       ERREUR    = -1;
    public static int       NULL      = 0;
    public static int       VAINQUEUR = 1;
    private Joueur          joueur;
    private int             nbArmee;
    private String          nom;
    private Plateau         plateau;
    private String          renfort;
    private ArrayList<Pays> voisins;

    @Deprecated
    public Pays(Joueur joueur, int nbArmee, String nom) {
        this.joueur  = joueur;
        this.nbArmee = nbArmee;
        this.nom     = nom;
        this.voisins = new ArrayList<Pays>();
        this.renfort = "";
    }

    public Pays(String nom, String renfort, Plateau plateau) {
        this.joueur  = null;
        this.renfort = renfort;
        this.nom     = nom;
        this.voisins = new ArrayList<Pays>();
        this.nbArmee = 0;
        this.plateau = plateau;
    }

    public String getRenfort() {
        return renfort;
    }

    public String getNom() {
        return nom;
    }

    public void setNom(String val) {
        this.nom = val;
    }

    public int getNbArmee() {
        return nbArmee;
    }

    public void setNbArmee(int val) {
        this.nbArmee = val;
    }

    public ArrayList<Pays> getVoisins() {
        return voisins;
    }

    public boolean ajouteVoisin(Pays val) {
        return this.voisins.add(val);
    }

    public Joueur getJoueur() {
        return joueur;
    }

    public void setJoueur(Joueur val) {
        this.joueur = val;
    }

    public boolean controlePays(Joueur val) {
        if (joueur.getNom().equals(val.getNom())) {
            return true;
        } else {
            return false;
        }
    }

    public void ajouteArmee(int renfort) {
        this.nbArmee += renfort;
    }

    public void retireArmee(int mort) {
        this.nbArmee -= mort;
    }

    public boolean testFrontiere(Pays voisin) {
        for (Pays pays : voisins) {
            if (pays.getNom().equals(voisin.getNom())) {
                return true;
            }
        }

        System.out.println("Erreur sur testFrontiere");

        return false;
    }

    public void initialiseVoisins(String fic) {
        String          pays_voisin = "";
        FileReader      fl          = null;
        BufferedReader  bf          = null;
        String          ligne       = null;
        StringTokenizer stok;

        try {
            File file = new File(fic);

            fl    = new FileReader(file);
            bf    = new BufferedReader(fl);
            ligne = bf.readLine();

            while (ligne != null) {
                stok = new StringTokenizer(ligne, " ");

                if (stok.nextToken().equals(this.getNom())) {
                    pays_voisin = stok.nextToken();

                    if (recherchePays(pays_voisin) == null) {
                        System.out.println("ERREUR méthode initialiseVoisins || introuvable => " + pays_voisin);

                        return;
                    }

                    ajouteVoisin(recherchePays(pays_voisin));
                }

                ligne = bf.readLine();
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            try {
                bf.close();
                fl.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }

    public Plateau getPlateau() {
        return plateau;
    }

    private Pays recherchePays(String nom) {
        for (Continent conti : plateau.getContinents()) {
            for (Pays pays : conti.getPaysContinent()) {
                if (pays.getNom().equals(nom)) {
                    return pays;
                }
            }
        }

        System.out.println("Erreur methode recherchePays");

        return null;
    }

    private static boolean verifieNbSoldatDeplacement(int nbSoldat, Pays p) {
        if (p.getNbArmee() > nbSoldat) {
            return true;
        }

        System.out.println("Erreur sur verifieNbSoldatDeplacement");

        return false;
    }

    private static boolean verifieNbSoldatAttaque(int nbSoldat, Pays p) {
        if (verifieNbSoldatDeplacement(nbSoldat, p) && (nbSoldat <= 3)) {
            return true;
        }

        System.out.println("Erreur sur verifieNbSoldatAttaque");

        return false;
    }

    private static boolean verifieNbSoldatDefense(int nbSoldat, Pays p) {
        if ((nbSoldat <= 2) && (nbSoldat <= p.getNbArmee())) {
            return true;
        }

        System.out.println("Erreur sur verifieNbSoldatDefense");

        return false;
    }

    public static ArrayList<Integer> jetAttaquant(int nbDe, Pays p) {
        ArrayList<Integer> jet = new ArrayList<Integer>(nbDe);
        Random             de  = new Random(System.currentTimeMillis());

        if (!verifieNbSoldatAttaque(nbDe, p)) {
            System.out.println("Trop attaquants");

            return null;
        }

        for (int i = 0; i < nbDe; i++) {
            sleep(1);
            jet.add(de.nextInt(6) + 1);
        }

        return jet;
    }

    public static ArrayList<Integer> jetDefenseur(int nbDe, Pays p) {
        ArrayList<Integer> jet = new ArrayList<Integer>(nbDe);
        Random             de  = new Random(System.currentTimeMillis());

        if (!verifieNbSoldatDefense(nbDe, p)) {
            System.out.println("Trop defenseurs");

            return null;
        }

        for (int i = 0; i < nbDe; i++) {
            sleep(1);
            jet.add(de.nextInt(6) + 1);
        }

        return jet;
    }

    public int simuleBataille(Pays defenseur, ArrayList<Integer> jetAttaque, ArrayList<Integer> jetDefense) {
        if ((jetAttaque == null) || (jetDefense == null)) {
            System.out.println("Certains jets de des sont null");

            return ERREUR;
        }

        Random             de              = new Random(System.currentTimeMillis());
        ArrayList<Integer> tabAttaque      = jetAttaque;
        ArrayList<Integer> tabDefense      = jetDefense;
        int                compteurAttaque = jetAttaque.size();

        // classement des meilleurs des
        Collections.sort(tabAttaque);
        Collections.sort(tabDefense);

        // resolution
        for (int i = 0; i < jetDefense.size(); i++) {
            System.out.println("de attaque=" + tabAttaque.get(tabAttaque.size() - 1 - i) + " <-> " + "de defense="
                               + tabDefense.get(tabDefense.size() - 1 - i));

            if (tabAttaque.get(tabAttaque.size() - 1 - i) <= tabDefense.get(tabDefense.size() - 1 - i)) {
                System.out.println("DEFENSE GAGNE !");
                retireArmee(1);
                compteurAttaque--;
            } else {
                System.out.println("ATTAQUE GAGNE !");
                defenseur.retireArmee(1);
            }
        }

        // test si attaque a reussi
        if (defenseur.getNbArmee() > 0) {

            // le defenseur a encore des armees sur le pays
            return NULL;
        } else {

            // attaque reussi, donc on renvoie le nb de soldats restants a deplacer
            return compteurAttaque;
        }
    }

    public int attaque(Pays defenseur, ArrayList<Integer> jetAttaque, ArrayList<Integer> jetDefense) {
        int resultat;

        // tests si tout ok
        if (!testFrontiere(defenseur)) {
            System.out.println("Erreur methode attaque");

            return ERREUR;
        }

        // bataille
        resultat = simuleBataille(defenseur, jetAttaque, jetDefense);

        // resolution bataille
        if (resultat >= VAINQUEUR) {
            if (!prendPossesion(defenseur, resultat)) {
                System.out.println("Erreur 2 methode attaque");

                return ERREUR;
            }

            System.out.println(getJoueur().getNom() + " PREND POSSESION DE " + defenseur.getNom());

            return VAINQUEUR;
        } else {
            return NULL;
        }
    }

    public boolean prendPossesion(Pays nouveauPays, int nbArmee) {
        nouveauPays.setJoueur(getJoueur());

        if (!deplaceArmeeVers(nouveauPays, nbArmee)) {
            System.out.println("Erreur methode prendPossesion");

            return false;
        }

        return true;
    }

    public boolean deplaceArmeeVers(Pays arrive, int nbArmee) {
        if (!testDeplacement(arrive) ||!verifieNbSoldatDeplacement(nbArmee, this)) {
            System.out.println("Erreur methode deplaceArmeeVers");

            return false;
        }

        // effectue le deplacement des armees
        this.nbArmee -= nbArmee;
        arrive.ajouteArmee(nbArmee);

        return true;
    }

    private static void sleep(long n) {
        try {
            Thread.sleep(n);
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    }

    @Override
    public String toString() {
        return this.nom;
    }

    /* TO DO : parcours en largeur sur les voisins allie */
    public boolean testDeplacement(Pays arrive) {
        return true;
    }
}
